﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;

namespace QModels
{
    public class CRC16Modbus
    {
        private const ushort POLYNOMIAL = 0xA001;
        private static readonly ushort[] crcTable = new ushort[256];

        static CRC16Modbus()
        {
            for (ushort i = 0; i < 256; i++)
            {
                ushort crc = i;
                for (int j = 0; j < 8; j++)
                {
                    if ((crc & 0x0001) != 0)
                    {
                        crc = (ushort)((crc >> 1) ^ POLYNOMIAL);
                    }
                    else
                    {
                        crc >>= 1;
                    }
                }
                crcTable[i] = crc;
            }
        }

        public static ushort ComputeChecksum(byte[] data)
        {
            ushort crc = 0xFFFF;

            foreach (byte b in data)
            {
                crc = (ushort)((crc >> 8) ^ crcTable[(crc ^ b) & 0xFF]);
            }

            return crc;
        }

        public static byte[] ComputeChecksumBytes(byte[] data)
        {
            ushort crc = ComputeChecksum(data);
            return new byte[] { (byte)(crc & 0xFF), (byte)(crc >> 8) };
        }

        public static byte[] GetBytesFromAddress(string address)
        {
            string hexString = address;
            byte[] abytes = new byte[hexString.Length / 2];
            for (int i = 0; i < abytes.Length; i++)
            {
                abytes[i] = Convert.ToByte(hexString.Substring(i * 2, 2), 16);
            }
            return abytes;
        }

        public static byte[] GetPlcBytesFromAddressWriter(ModBusTcpAddress tcpAddress,int value)
        {
            var t_0 = $"{tcpAddress.plc}{tcpAddress.readOrWrite}{tcpAddress.address}{tcpAddress.readLen}";
            var t_bytes = GetBytesFromAddress(t_0);
            var crcs = ComputeChecksumBytes(t_bytes);
            var res = new byte[t_bytes.Length + crcs.Length];
            var index = 0;
            for (int i = 0; i < t_bytes.Length; i++) res[index++] = t_bytes[i];
            for (int i = 0; i < crcs.Length; i++) res[index++] = crcs[i];
            return res;
        }

        public static byte[] GetPlcBytesFromAddress(ModBusTcpAddress tcpAddress)
        {
            var t_0 = $"{tcpAddress.plc}{tcpAddress.readOrWrite}{tcpAddress.address}{tcpAddress.readLen}";
            var t_bytes = GetBytesFromAddress(t_0);
            var crcs = ComputeChecksumBytes(t_bytes);
            var res = new byte[t_bytes.Length + crcs.Length];
            var index = 0;
            for (int i = 0; i < t_bytes.Length; i++) res[index++] = t_bytes[i];
            for (int i = 0; i < crcs.Length; i++) res[index++] = crcs[i];
            return res;
        }

        public static byte[] GetPlcBytesFromAddress(string address,string plc="01",string readOrWrite="03",string readLen = "0001")
        {
            var t_0 = $"{plc}{readOrWrite}{address}{readLen}";
            var t_bytes = GetBytesFromAddress(t_0);
            var crcs = ComputeChecksumBytes(t_bytes);
            var res= new byte[t_bytes.Length+crcs.Length];
            var index = 0;
            for(int i=0; i<t_bytes.Length; i++) res[index++]=t_bytes[i];
            for(int i=0;i<crcs.Length; i++) res[index++] = crcs[i];
            return res;
        }
        public static int GetValueFromModulBus_Int(ReadOnlySpan<byte> data)
        {



            string hexString = Convert.ToHexString(data);
            return GetValueFromModulBus_Int(hexString);
        }
        public static int GetValueFromModulBus_Int(string hexString)
        {
            var dataLen = int.Parse(hexString.AsSpan().Slice(4, 2).ToString());
            var hexStr = hexString.AsSpan().Slice(6, dataLen * 2).ToString();
            int decimalValue = int.Parse(hexStr, System.Globalization.NumberStyles.HexNumber);


            return decimalValue;
        }
        public static float GetValueFromModulBus_Float(ReadOnlySpan<byte> data)
        {



            string hexString = Convert.ToHexString(data);
            return GetValueFromModulBus_Float(hexString);
           
        }
        public static float GetValueFromModulBus_Float(string hexString)
        {
            var dataLen = int.Parse(hexString.AsSpan().Slice(4, 2).ToString());
            var hexStr = hexString.AsSpan().Slice(6, dataLen * 2).ToString();
            uint intBits = Convert.ToUInt32(hexStr, 16);
            float floatValue = BitConverter.ToSingle(BitConverter.GetBytes(intBits), 0);


            return floatValue;
        }



    }
}
